﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Proggy.Data.Abstract;
using Proggy.Data.Entities;
using System.Configuration;
using System.Web.Mvc;
using System.Web;
using Proggy.Web.Cms.Cache;
using Proggy.Web.Cms.Sections;
using System.Reflection;
using Proggy.Data.Concrete;
using System.Threading;
using Proggy.Web.Cms.Seo.Service.Abstract;
using WURFL.Aspnet.Extensions.Config;
using WURFL;
using Proggy.Web.Cms.Repositories.ContentModel;
using Proggy.Web.Cms.ContentModel;

namespace Proggy.Web.Cms.AppHelpers
{
    /// <summary>
    /// Returns data for app startup
    /// </summary>
    public class StartupManager
    {
        #region private fields / methods

        /// <summary>
        /// The nodeRepository
        /// </summary>
        private INodeRepository _nodeRepo;

        /// <summary>
        /// Returns a route url from a node (url)
        /// </summary>
        private string getUrlForRoute(PublishableNode n)
        {
            var urlForRoute = UrlCache.GetUrlFromNodeId(n.PublishableNodeId).TrimStart('/');
            return urlForRoute;
        }

        #endregion

        #region public methods / properties (inc static)

        /// <summary>
        /// Sets or resets node repo and all published nodes to fresh copy of data
        /// </summary>
        public void RefreshData()
        {
            // set repo
            this._nodeRepo = DependencyResolver.Current.GetService<INodeRepository>();

            // set all published nodes
            AllPublishedNodes =
                this._nodeRepo.GetPublishableNodes(true).ToList();
        }

        /// <summary>
        /// Dispose data context
        /// </summary>
        public void DisposeDataContext()
        {
            this._nodeRepo.DisposeDataContext();
        }

        /// <summary>
        /// Returns the routes for all nodes in the CMS
        /// </summary>
        /// <returns></returns>
        public List<ProggyRoute> GetOrderedNodeRoutes()
        {
            // check url cache
            if (UrlCache.CachedNodeUrls == null)
            {
                throw new Exception("Please call \"SetUrlCache()\" before calling this method.");
            }

            // get nodes explicitly
            var nodes = AllPublishedNodes
                //.Where(x => !x.IsRoot) // exclude home
                .OrderByDescending(n => n.LevelInTree)
                .ThenByDescending(n => n.OrderInParent)
                .ToList();

            // get home node
            var homeNode = nodes.SingleOrDefault(x => x.IsRoot);

            // create output
            var output = new List<ProggyRoute>();

            // check home node
            if (homeNode != null)
            {
                // add normal routes to output
                nodes.Where(x => !x.IsRoot).ToList().ForEach(n =>
                {
                    // get url
                    var url = this.getUrlForRoute(n);

                    // add route
                    output.Add(new ProggyRoute
                    {
                        Name = "Proggy_Route_" + n.PublishableNodeId.ToString(),
                        UrlWithParameters = url,// + (n.UrlPortion == "" ? "" : "/") + "{action}/{id}",
                        ParameterDefaults = new
                        {
                            controller = n.TypeAlias,
                            action = "HandleUrl",
                            nodeId = n.PublishableNodeId /*url = url,*/
                            //id = UrlParameter.Optional,
                            //json = false // needed for "proggylink"
                        },
                        NameSpaces = new[] { n.ControllerNameSpace }
                    });

                });

                //// add json routes to output
                //nodes.Where(x => !x.IsRoot).ToList().ForEach(n =>
                //{
                //    // get url
                //    var url = this.getUrlForRoute(n);

                //    // add route
                //    output.Add(new ProggyRoute
                //    {
                //        Name = "Proggy_Json_Route_" + n.PublishableNodeId.ToString(),
                //        UrlWithParameters = "json" + (n.IsRoot ? "" : "/") + url,// + (n.IsRoot ? "" : "/") + "{action}/{id}",
                //        ParameterDefaults = new
                //        {
                //            controller = n.TypeAlias,
                //            action = "JsonHandleUrl",
                //            nodeId = n.PublishableNodeId, /*url = url,*/
                //            //id = UrlParameter.Optional,
                //            json = true // needed for "proggylink"
                //        },
                //        NameSpaces = new[] { n.ControllerNameSpace }
                //    });

                //});

                //// add json default
                //output.Add(new ProggyRoute
                //{
                //    Name = "JsonDefault",
                //    UrlWithParameters = "json",///{action}/{id}",
                //    ParameterDefaults = new
                //    {
                //        controller = homeNode.TypeAlias,
                //        action = "JsonHandleUrl",
                //        /*url = url,*/
                //        nodeId = homeNode.PublishableNodeId,
                //        //id = UrlParameter.Optional,
                //        json = true // needed for "proggylink"
                //    },
                //    NameSpaces = new[] { homeNode.ControllerNameSpace }
                //});

                // add default
                output.Add(new ProggyRoute
                {
                    Name = "Default",
                    UrlWithParameters = "",//"{action}/{id}",
                    ParameterDefaults = new
                    {
                        controller = homeNode.TypeAlias,
                        action = "HandleUrl",
                        nodeId = homeNode.PublishableNodeId
                        //id = UrlParameter.Optional,
                        //json = false // needed for "proggylink"
                    },
                    NameSpaces = new[] { homeNode.ControllerNameSpace }
                });
            }

            //
            return output;

        }

        /// <summary>
        /// Returns urls for cache
        /// </summary>
        /// <returns></returns>
        public void SetUrlCache(string rootUrl)
        {
            // check
            if (AllPublishedNodes == null) {
                RefreshData();
            }

            // get all nodes
            var nodes = AllPublishedNodes;

            // start output
            var output = new List<CachedNodeUrl>();

            // get service
            var seoService = DependencyResolver.Current.GetService<IUrlOptimizationService>();
            string leftPart = ConfigurationManager.AppSettings["UrlLeftPart"];
            if (string.IsNullOrEmpty(leftPart)) leftPart = "http://abc.def.ghi.jkl.m.com";

            // loop 
            foreach (var node in nodes)
            {

                // check home
                if (node.IsRoot)
                {
                    output.Add(new CachedNodeUrl { NodeId = node.PublishableNodeId, NodeUrl = rootUrl });
                }
                else // other nodes
                {
                    // start url
                    var url = string.Empty;

                    // get current for inner loop
                    var currentNode = node;

                    //
                    while (currentNode.HasParent)
                    {
                        // add to url
                        url = rootUrl + currentNode.UrlPortion + url;

                        // change current
                        currentNode = currentNode.ParentNode;
                    }

                    // check
                    if (string.IsNullOrEmpty(leftPart)) leftPart = "http://test.test.co.com.ignore";

                    // get url / bool
                    var boolUrl = seoService.IsOptimizedOkAlready(new Uri(leftPart + url));

                    // check
                    if (!boolUrl.Item1)
                    {
                        url = boolUrl.Item2.AbsolutePath;
                    }

                    // add to cache
                    output.Add(new CachedNodeUrl { NodeUrl = url, NodeId = node.PublishableNodeId });
                }
            }

            //
            UrlCache.CachedNodeUrls = output;
        }

        /// <summary>
        /// Sets the view model cache
        /// </summary>
        public void SetPublishedContentCache()
        {
            // 
            var maxSizeSetting = ConfigurationManager.AppSettings["MaxCacheSize"];

            //
            var typeRepo = DependencyResolver.Current.GetService<IContentModelTypeRepository>();
            var conv = DependencyResolver.Current.GetService<IContentModelConverter>();

            // check
            if (string.IsNullOrEmpty(maxSizeSetting))
            {
                Cache.CachedContentManager.SetCache(typeRepo,conv);
            }
            else
            {
                Cache.CachedContentManager.SetCache(typeRepo, conv,Convert.ToInt32(maxSizeSetting));
            }
        }

        /// <summary>
        /// Returns sections for backend
        /// </summary>
        /// <returns></returns>
        public void SetSections()
        {
            // output
            var output = new List<ISection>();

            // type
            var iSectionType = typeof(ISection);

            // get assemblies
            var assemblies = AppDomain.CurrentDomain.GetAssemblies();

            // iterate
            foreach (var assembly in assemblies)
            {
                foreach (var type in assembly.GetTypes())
                {

                    // check if ISection exists
                    var exists = type.GetInterfaces().Contains(iSectionType);

                    //
                    if (exists)
                    {
                        // create instance
                        var instance = Activator.CreateInstance(type);

                        // add
                        output.Add((ISection)instance);
                    }

                }
            }

            // set
            BackEndSections.Sections = output.OrderBy(s => s.OrderInNav).ToList();
        }

        /// <summary>
        /// All published node (refresh using "refreshdata" method)
        /// </summary>
        public static List<PublishableNode> AllPublishedNodes { get; set; }

        /// <summary>
        /// Set Wurfl
        /// </summary>
        public void SetWurfl()
        {
            if (WurflManager == null && HttpRuntime.Cache != null)
            {
                // 
                var configurer = new ApplicationConfigurer();
                WurflManager = WURFLManagerBuilder.Build(configurer);
                HttpRuntime.Cache["WURFL_MANAGER_KEY"] = WurflManager;
            }
        }

        /// <summary>
        /// Wurfl Manager
        /// </summary>
        public static IWURFLManager WurflManager { get; set; }

        #endregion        
    }
}
